﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using Icoders.MarketTracker.Core.MasterData;
using Icoders.MarketTracker.Core.Repository.MasterDataRepositories;
using Icoders.MarketTracker.Core.Validation;
using Icoders.MarketTracker.Data.EF;
using Icoders.MarketTracker.Data.Utils;
using Icoders.MarketTracker.Data.Utils.Caching;

namespace Icoders.MarketTracker.Data.Repository.MasterDataRepositories
{
    public class ProductRepository :RepositoryBase, IProductRepository
    {
        
       private AppDataContext _ctx;
       private ICacheProvider _cacheProvider;

        public ProductRepository(AppDataContext ctx, ICacheProvider cacheProvider)
        {
            _ctx = ctx;
            _cacheProvider = cacheProvider;
        }

        public ValidationResultInfo Validate(Product objToValidate)
        {
            ValidationResultInfo vri = objToValidate.BasicValidation();
            bool hasDuplicateName = GetAll().Where(v => v.Id != objToValidate.Id)
                .Any(p => p.Name == objToValidate.Name);
            if (hasDuplicateName)
                vri.Results.Add(new ValidationResult("Duplicate Name Found"));
            return vri;
        }

        public int Save(Product entity)
        {
            ValidationResultInfo vri = Validate(entity);
            if (!vri.IsValid)
            {
                throw new DomainValidationException(vri, "Product Details provided not valid");
            }
            DateTime date = TimeUtil.GetDateTime();
            TblProduct tbl = _ctx.TblProduct.FirstOrDefault(s => s.Id == entity.Id);
            if (tbl == null)
            {
                tbl = new TblProduct();
                tbl.CreatedOn = date;
                tbl.StatusId = (int)MasterEntityStatus.New;
                tbl.Code = entity.Code;
                _ctx.TblProduct.AddObject(tbl);
            }
            tbl.UpdatedOn = date;
            tbl.Name = entity.Name;
            tbl.Description = entity.Description;
            tbl.ClientId = entity.ClientId;
            tbl.Milles = entity.Milles;
            tbl.Price = entity.Price;
            tbl.BrandId = entity.ProductBrandId;
            _ctx.SaveChanges();
            _cacheProvider.Put(_cacheListKey, _ctx.TblProduct.Where(x => x.StatusId != 3).Select(s => s.Id).ToList());
            _cacheProvider.Remove(string.Format(_cacheKey, tbl.Id));
            return tbl.Id;
        }

        public Product GetById(int id)
        {
            Product entity = (Product)_cacheProvider.Get(string.Format(_cacheKey, id));
            if (entity == null)
            {
                var tbl = _ctx.TblProduct.FirstOrDefault(s => s.Id == id);
                if (tbl != null)
                {
                    entity = Map(tbl);
                    _cacheProvider.Put(string.Format(_cacheKey, entity.Id), entity);
                }

            }
            return entity;
        }

        public List<Product> GetAll()
        {
           // return _ctx.TblProduct.ToList().Where(p => p.StatusId != (int)MasterEntityStatus.Deleted).Select(n => Map(n)).ToList();
            IList<Product> entities = null;
            IList<int> ids = (IList<int>)_cacheProvider.Get(_cacheListKey);
            if (ids != null)
            {
                entities = new List<Product>(ids.Count);
                foreach (int id in ids)
                {
                    Product entity = GetById(id);
                    if (entity != null)
                        entities.Add(entity);
                }
            }
            else
            {
                entities = _ctx.TblProduct.Where(x => x.StatusId != 3).ToList().Select(s => Map(s)).ToList();
                if (entities != null && entities.Count > 0)
                {
                    ids = entities.Select(s => s.Id).ToList(); //new List<int>(persons.Count);
                    _cacheProvider.Put(_cacheListKey, ids);
                    foreach (Product p in entities)
                    {
                        _cacheProvider.Put(string.Format(_cacheKey, p.Id), p);
                    }

                }
            }
            return entities.ToList();
        }

        public void Delete(int id)
        {
            var tbl = _ctx.TblProduct.FirstOrDefault(s => s.Id == id);
            if (tbl != null)
            {
                tbl.StatusId = (int)MasterEntityStatus.Deleted;
                _ctx.SaveChanges();
                _cacheProvider.Put(_cacheListKey, _ctx.TblProduct.Where(x => x.StatusId != 3).Select(s => s.Id).ToList());
                _cacheProvider.Remove(string.Format(_cacheKey, tbl.Id));
            }
        }

        public List<Product> GetByClient(int clientId)
        {
            return GetAll().Where(s => s.ClientId == clientId).ToList().ToList();
        }

        private Product Map(TblProduct tbl)
        {
            return new Product
            {
                Id = tbl.Id,
                Name = tbl.Name,
                Description = tbl.Description,
                Code = tbl.Code,
                UpdatedOn = tbl.UpdatedOn,
                ClientId=tbl.ClientId,
                ClientName=tbl.TblClient.Name,
                Status = (MasterEntityStatus)tbl.StatusId,
                CreatedOn = tbl.CreatedOn,
                Price=tbl.Price,
                Milles=tbl.Milles.Value,
                ProductBrandId=tbl.BrandId

            };
        }

        protected override string _cacheKey
        {
            get { return "Product-{0}"; }
        }

        protected override string _cacheListKey
        {
            get { return "ProductList"; }
        }
    }
}
